﻿using UnityEngine;
using ZCUtil.Math;

namespace ZCUtil.Touch
{
    /// <summary>
    /// Touch工具
    /// </summary>
    public class TouchPoint
    {
        #region StaticField
        private static Vector3 ZERO = Vector3.zero;
        #endregion

        #region PrivateField
        /// <summary>
        /// 开始点、中心点、结束点
        /// </summary>
        private Vector3 m_StartPoint, m_MidPoint, m_EndPoint;

        /// <summary>
        /// 3点长度
        /// </summary>
        private float m_Distance = 0.0f;

        /// <summary>
        /// 首次Down
        /// </summary>
        private bool m_FirstDraw = false;
        
        /// <summary>
        /// 插值结果
        /// </summary>
        private Vector3[] m_Points = null;

        /// <summary>
        /// 插值间隔
        /// </summary>
        private float m_Space = 1.0f;

        /// <summary>
        /// 每一笔的最小点
        /// </summary>
        private Vector3 m_MinPoint = Vector3.one * 9.9e9f;
        
        /// <summary>
        /// 每一笔的最大点
        /// </summary>
        private Vector3 m_MaxPoint = -Vector3.one * 9.9e9f;
        #endregion

        #region PublicMethod
        public bool FirstDraw => m_FirstDraw;

        public float Distance => m_Distance;

        public Vector3[] Points => m_Points;

        public Vector3 MinPoint => m_MinPoint;

        public Vector3 MaxPoint => m_MaxPoint;
        #endregion

        #region PublicMethod
        /// <summary>
        /// 构造函数
        /// </summary>
        public TouchPoint()
        {
            m_StartPoint = m_MidPoint = m_EndPoint = ZERO;
        }

        /// <summary>
        /// 设置鼠标Touch进去的点
        /// </summary>
        /// <param name="point"></param>
        public void SetPoint(Vector3 point)
        {
            if (!m_FirstDraw)
            {
                m_FirstDraw = true;
            }
            if (m_StartPoint == ZERO && m_MidPoint == ZERO && m_EndPoint == ZERO)
            {
                m_StartPoint = m_MidPoint = m_EndPoint = point;
            }
            else
            {
                if (Vector3.Distance(m_EndPoint, point) <= m_Space)
                {
                    m_Points = null;
                    return;
                }

                m_StartPoint = m_MidPoint;
                m_MidPoint = m_EndPoint;
                m_EndPoint = point;

                CalcMaxMinPoint();
                CalcBezierPoints();
            }
        }

        /// <summary>
        /// 清除缓存点
        /// </summary>
        public void Clear()
        {
            m_Distance = 0.0f;
            m_Points = null;
        }

        /// <summary>
        /// 结束一笔
        /// </summary>
        public void DropTouch()
        {
            m_StartPoint = m_MidPoint = m_EndPoint = ZERO;
            m_FirstDraw = false;
            m_Distance = 0.0f;
            m_Points = null;

            m_MinPoint = Vector3.one * 9.9e9f;
            m_MaxPoint = -Vector3.one * 9.9e9f;
        }
        #endregion

        #region PrivateMethod
        /// <summary>
        /// 计算最小点
        /// </summary>
        private void CalcMaxMinPoint()
        {
            m_MaxPoint.x = Mathf.Max(m_StartPoint.x, m_MidPoint.x, m_EndPoint.x, m_MaxPoint.x);
            m_MaxPoint.y = Mathf.Max(m_StartPoint.y, m_MidPoint.y, m_EndPoint.y, m_MaxPoint.y);
            m_MaxPoint.z = Mathf.Max(m_StartPoint.z, m_MidPoint.z, m_EndPoint.z, m_MaxPoint.z);

            m_MinPoint.x = Mathf.Min(m_StartPoint.x, m_MidPoint.x, m_EndPoint.x, m_MinPoint.x);
            m_MinPoint.y = Mathf.Min(m_StartPoint.y, m_MidPoint.y, m_EndPoint.y, m_MinPoint.y);
            m_MinPoint.z = Mathf.Min(m_StartPoint.z, m_MidPoint.z, m_EndPoint.z, m_MinPoint.z);
        }

        /// <summary>
        /// 计算最大点
        /// </summary>
        private void CalcBezierPoints()
        {
            Vector3 startPoint = (m_StartPoint + m_MidPoint) / 2.0f;
            Vector3 midPoint = m_MidPoint;
            Vector3 endPoint = (m_MidPoint + m_EndPoint) / 2.0f;
            m_Distance = Vector3.Distance(startPoint, midPoint) + Vector3.Distance(midPoint, endPoint);
            int count = (int)(m_Distance / m_Space);
            Bezier bezier = new Bezier(startPoint, midPoint, endPoint, count);
            m_Points = bezier.Vertexs.ToArray();
        }
        #endregion
    }
}
